﻿using System;
using System.Collections.Generic;
using System.Text;
using ArcEngine.Resources;
using ArcEngine;
using System.Drawing;
using ArcEngine.Graphics;


namespace DungeonEye
{

	/// <summary>
	/// Represents the player's heroes in the dungeon
	/// </summary>
	static public class Team
	{

		/// <summary>
		/// Initialize the team
		/// </summary>
		/// <returns></returns>
		static public bool Init()
		{

			// Load heroes
			Heroes = new Hero[6];
			for (int i = 0; i < 4; i++)
			{
				Hero hero = new Hero("Hero " + i);
				hero.Generate();

				Heroes[i] = hero;
			}

			return true;
		}



		/// <summary>
		/// Update the team status
		/// </summary>
		static public void Update()
		{
		}



		/// <summary>
		/// Display team informations
		/// </summary>
		static public void Draw()
		{


			for (int y = 0; y < 3; y++)
			{
				for (int x = 0; x < 2; x++)
				{
					Hero hero = Heroes[y * 2 + x];
					if (hero == null)
						continue;

					//hero.DrawHead(new Point(368 + 144 * x, y * 104));


					hero.DrawHead(new Point(368 + 144 * x, y * 104 + 22));

					Video.Font.Color = Color.White;
					Video.DrawText(new Point(368 + 144 * x + 4, y * 104 - 2), hero.Name);
					Video.DrawText(new Point(368 + 144 * x + 4, y * 104 + 81), hero.hp + " of " + hero.maxHP);

				}
			}

		}



		/// <summary>
		/// Does the Team can see this place
		/// </summary>
		/// <param name="mz">Maze</param>
		/// <param name="loc">Place to see</param>
		/// <returns>True if can see the location</returns>
		static public bool CanSee(Maze mz, Point loc)
		{
			Point dist = Point.Empty;

			// Not the same maze
			if (Maze != mz)
				return false;


			Rectangle rect = Rectangle.Empty;
			switch (Direction)
			{
				case Compass.North:
				{
					if (!new Rectangle(Location.X - 1, Location.Y - 3, 3, 4).Contains(loc) &&
						loc != new Point(Location.X - 3, Location.Y - 3) &&
						loc != new Point(Location.X - 2, Location.Y - 3) &&
						loc != new Point(Location.X - 2, Location.Y - 2) &&
						loc != new Point(Location.X + 3, Location.Y - 3) &&
						loc != new Point(Location.X + 2, Location.Y - 3) &&
						loc != new Point(Location.X + 2, Location.Y - 2))
							return false;

					// Is there a wall between the Team and the location
					int dx = loc.X - Location.X;
					int dy = loc.Y - Location.Y;
					float delta = (float)dy / (float)dx;
					float y = 0;
					for (int pos = Location.Y; pos >= loc.Y; pos--)
					{
						if (Maze.GetWallID(new Point(pos, Location.Y + (int)y)) != 0)
							return false;

						y += delta;
					}

					return true;
				}

				case Compass.South:
				{
					if (!new Rectangle(Location.X - 1, Location.Y, 3, 4).Contains(loc) &&
						loc != new Point(Location.X - 3, Location.Y + 3) &&
						loc != new Point(Location.X - 2, Location.Y + 3) &&
						loc != new Point(Location.X - 2, Location.Y + 2) &&
						loc != new Point(Location.X + 3, Location.Y + 3) &&
						loc != new Point(Location.X + 2, Location.Y + 3) &&
						loc != new Point(Location.X + 2, Location.Y + 2))
							return false;


					// Is there a wall between the Team and the location
					int dx = loc.X - Location.X;
					int dy = loc.Y - Location.Y;
					float delta = (float)dy / (float)dx;
					float y = 0;
					for (int pos = Location.Y; pos <= loc.Y; pos++)
					{
						if (Maze.GetWallID(new Point(pos, Location.Y + (int)y)) != 0)
							return false;

						y += delta;
					}

					return true;
				}

				case Compass.West:
				{
					if (!new Rectangle(Location.X - 3, Location.Y - 1, 4, 3).Contains(loc) &&
						loc != new Point(Location.X - 3, Location.Y - 3) &&
						loc != new Point(Location.X - 3, Location.Y - 2) &&
						loc != new Point(Location.X - 2, Location.Y - 2) &&
						loc != new Point(Location.X - 3, Location.Y + 3) &&
						loc != new Point(Location.X - 3, Location.Y + 2) &&
						loc != new Point(Location.X - 2, Location.Y + 2))
							return false;



					// Is there a wall between the Team and the location
					int dx = loc.X - Location.X;
					int dy = loc.Y - Location.Y;
					float delta = (float)dy / (float)dx;
					float y = 0;
					for (int pos = Location.X; pos >= loc.X; pos--)
					{
						if (Maze.GetWallID(new Point(pos, Location.Y + (int)y)) != 0)
							return false;

						y += delta;
					}

					return true;
				}

				case Compass.East:
				{
					if (!new Rectangle(Location.X, Location.Y - 1, 4, 3).Contains(loc) &&
						loc != new Point(Location.X + 3, Location.Y - 3) &&
						loc != new Point(Location.X + 3, Location.Y - 2) &&
						loc != new Point(Location.X + 2, Location.Y - 2) &&
						loc != new Point(Location.X + 3, Location.Y + 3) &&
						loc != new Point(Location.X + 3, Location.Y + 2) &&
						loc != new Point(Location.X + 2, Location.Y + 2))
							return false;

					// Is there a wall between the Team and the location
					int dx = loc.X - Location.X;
					int dy = loc.Y - Location.Y;
					float delta = (float)dy / (float)dx;
					float y = 0;
					for (int pos = Location.X; pos <= loc.X; pos++)
					{
						if (Maze.GetWallID(new Point(pos, Location.Y + (int)y)) != 0)
							return false;

						y += delta;
					}

					return true;
				}

			}

			return false;
		}



		/// <summary>
		/// Returns the distance between the Team and a location
		/// </summary>
		/// <param name="loc">Location to check</param>
		/// <returns>Distance with the Team</returns>
		static public Point Distance(Point loc)
		{
			return new Point(loc.X - Location.X, loc.Y - Location.Y);
		}



		#region Movement

		/// <summary>
		/// Rotate the team
		/// </summary>
		/// <param name="rot"></param>
		static public void Rotate(TeamRotation rot)
		{
			switch (direction)
			{
				case Compass.North:
				{
					switch (rot)
					{
						case TeamRotation.Clockwise:
						{
							direction = Compass.East;
						}
						break;

						case TeamRotation.CounterClockwise:
						{
							direction = Compass.West;
						}
						break;

						case TeamRotation.UTurn:
						{
							direction = Compass.South;
						}
						break;
					}
				}
				break;

				case Compass.South:
				{
					switch (rot)
					{
						case TeamRotation.Clockwise:
						{
							direction = Compass.West;
						}
						break;

						case TeamRotation.CounterClockwise:
						{
							direction = Compass.East;
						}
						break;

						case TeamRotation.UTurn:
						{
							direction = Compass.North;
						}
						break;
					}
				}
				break;

				case Compass.East:
				{
					switch (rot)
					{
						case TeamRotation.Clockwise:
						{
							direction = Compass.South;
						}
						break;

						case TeamRotation.CounterClockwise:
						{
							direction = Compass.North;
						}
						break;

						case TeamRotation.UTurn:
						{
							direction = Compass.West;
						}
						break;
					}
				}
				break;

				case Compass.West:
				{
					switch (rot)
					{
						case TeamRotation.Clockwise:
						{
							direction = Compass.North;
						}
						break;

						case TeamRotation.CounterClockwise:
						{
							direction = Compass.South;
						}
						break;

						case TeamRotation.UTurn:
						{
							direction = Compass.East;
						}
						break;
					}
				}
				break;
			}
		}



		/// <summary>
		/// Move the team
		/// </summary>
		/// <param name="front"></param>
		/// <param name="strafe"></param>
		/// <rereturns>True if move allowed, otherwise false</rereturns>
		///TODO Check collision with monster
		static public bool Move(int front, int strafe)
		{
			switch (direction)
			{
				case Compass.North:
				{
					if (maze.GetWallID(new Point(location.X + front, location.Y + strafe)) == 0)
					{
						location.X += front;
						location.Y += strafe;

						return true;
					}
					else
						DungeonEye.AddDisplayMessage("You can't go that way.", Color.White);

				}
				break;

				case Compass.South:
				{
					if (maze.GetWallID(new Point(location.X - front, location.Y - strafe)) == 0)
					{
						location.X -= front;
						location.Y -= strafe;
						return true;
					}
					else
						DungeonEye.AddDisplayMessage("You can't go that way.", Color.White);
				}
				break;

				case Compass.East:
				{
					if (maze.GetWallID(new Point(location.X - strafe, location.Y + front)) == 0)
					{
						location.X -= strafe;
						location.Y += front;
						return true;
					}
					else
						DungeonEye.AddDisplayMessage("You can't go that way.", Color.White);
				}
				break;

				case Compass.West:
				{
					if (maze.GetWallID(new Point(location.X + strafe, location.Y - front)) == 0)
					{
						location.X += strafe;
						location.Y -= front;
						return true;
					}
					else
						DungeonEye.AddDisplayMessage("You can't go that way.", Color.White);
				}
				break;
			}

			return false;
		}


		#endregion




		#region Properties


		/// <summary>
		/// All heros in the team
		/// </summary>
		static public Hero[] Heroes;


		/// <summary>
		/// Number of heroes in the team
		/// </summary>
		static public int HeroCount
		{
			get
			{
				int count = 0;
				foreach (Hero hero in Heroes)
				{
					if (hero != null)
						count++;
				}

				return count;
			}
		}


		/// <summary>
		/// The direction the team is facing
		/// </summary>
		static public Compass Direction
		{
			get
			{
				return direction;
			}
			set
			{
				direction = value;
			}
		}
		static Compass direction;


		/// <summary>
		/// Location of the team
		/// </summary>
		static public Point Location
		{
			get
			{
				return location;
			}
			set
			{
				location = value;
			}
		}
		static Point location;


		/// <summary>
		/// Current maze
		/// </summary>
		static public Maze Maze
		{
			get
			{
				return maze;
			}
			set
			{
				maze = value;
			}
		}
		static Maze maze;


		/// <summary>
		/// Return the currently selected hero
		/// </summary>
		static public Hero CurrentHero
		{
			get
			{
				return Heroes[heroID];
			}
		}


		/// <summary>
		/// Sets the hero to select
		/// </summary>
		static public int SelectHero
		{
			set
			{
				if (value < HeroCount && value >= 0)
					heroID = value;
			}
		}
		static int heroID;

		#endregion
	}


	/// <summary>
	/// Compass direction
	/// </summary>
	public enum Compass
	{
		North,
		East,
		South,
		West
	}


	/// <summary>
	/// Type of rotation
	/// </summary>
	public enum TeamRotation
	{
		Clockwise,
		CounterClockwise,
		UTurn
	}
}
